package net.stuffrepos.bricknetcenter.util.validation;

import java.util.Date;
import javax.persistence.Column;
import net.stuffrepos.bricknetcenter.util.BuilderFactory;
import net.stuffrepos.bricknetcenter.util.BuilderFactory.Builder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Eduardo H. Bogoni <eduardobogoni@gmail.com>
 */
public class ConstraintFactory {

    private static final Log log = LogFactory.getLog(ConstraintFactory.class);
    private static final BuilderFactory.ClassKeyed<Property, Constraint> constraintBuilders = new BuilderFactory.ClassKeyed<Property, Constraint>(true) {

        @Override
        protected Class getSourceKey(Property source) {
            return source.getPropertyType();
        }
    };

    static {
        constraintBuilders.addBuilder(Integer.class, new Builder<Property, Constraint>() {

            @Override
            public Constraint build(Property property) {
                return new IntegerConstraint(
                        isPropertyRequired(property),
                        minValueConstraint(property),
                        maxValueConstraint(property));
            }
        });
        constraintBuilders.addBuilder(String.class, new Builder<Property, Constraint>() {

            @Override
            public Constraint build(Property property) {
                return new StringConstraint(
                        isPropertyRequired(property),
                        minLengthConstraint(property),
                        maxLengthConstraint(property));
            }
        });
        constraintBuilders.addBuilder(Date.class, new Builder<Property, Constraint>() {

            @Override
            public Constraint build(Property property) {
                return new DefaultConstraint(isPropertyRequired(property));
            }
        });
        constraintBuilders.addBuilder(Enum.class, new Builder<Property, Constraint>() {

            @Override
            public Constraint build(Property property) {
                return new DefaultConstraint(isPropertyRequired(property));
            }
        });
    }

    public static Constraint getFromEntityProperty(Class entityClass, String propertyName) {
        return getFromEntityProperty(Property.getProperty(entityClass, propertyName));
    }

    public static Constraint getFromEntityProperty(Property property) {
        return constraintBuilders.getResult(property);
    }

    private static interface ConstraintBuilder {

        public Constraint build(Property property);
    }

    private static boolean isPropertyRequired(Property property) {
        return property.hasAnnotation(Column.class) && !((Column) property.getAnnotation(Column.class)).nullable();
    }

    private static Integer minValueConstraint(Property property) {
        if (property.hasAnnotation(ConstraintAnnotation.class)) {
            return ((ConstraintAnnotation) property.getAnnotation(ConstraintAnnotation.class)).minValue();
        } else {
            return null;
        }
    }

    private static Integer maxValueConstraint(Property property) {
        if (property.hasAnnotation(ConstraintAnnotation.class)) {
            return ((ConstraintAnnotation) property.getAnnotation(ConstraintAnnotation.class)).maxValue();
        } else {
            return null;
        }
    }

    private static Integer minLengthConstraint(Property property) {
        return minValueConstraint(property);
    }

    private static Integer maxLengthConstraint(Property property) {
        if (property.hasAnnotation(Column.class)) {
            return ((Column) property.getAnnotation(Column.class)).length();
        } else {
            return maxValueConstraint(property);
        }
    }
}
